package com.leicx.guli.product.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.leicx.guli.common.utils.PageUtils;
import com.leicx.guli.common.utils.Query;
import com.leicx.guli.product.dao.CategoryDao;
import com.leicx.guli.product.entity.CategoryEntity;
import com.leicx.guli.product.service.CategoryService;
import com.leicx.guli.product.vo.catalog.Catalog1Vo;
import com.leicx.guli.product.vo.catalog.Catalog2Vo;
import com.leicx.guli.product.vo.catalog.Catalog3Vo;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


@Service("categoryService")
public class CategoryServiceImpl extends ServiceImpl<CategoryDao, CategoryEntity> implements CategoryService {

    @Resource
    StringRedisTemplate stringRedisTemplate;

    private static final String CATALOG_JSON = "catalogJson";

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<CategoryEntity> page = this.page(
                new Query<CategoryEntity>().getPage(params),
                new QueryWrapper<CategoryEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<CategoryEntity> listTree() {
        // 获取所有的商品分类
        List<CategoryEntity> categoryEntities = baseMapper.selectList(null);
        // 找到一级商品目录，组装成属性结构返回
        return categoryEntities.stream()
                .filter(q -> q.getParentCid() == 0)
                .peek(q -> setChildren(q, categoryEntities))
                .sorted(Comparator.comparingInt(CategoryEntity::getSort))
                .collect(Collectors.toList());
    }

    private void setChildren(CategoryEntity root, List<CategoryEntity> all) {
        List<CategoryEntity> collect = all.stream()
                .filter(q -> Objects.equals(q.getParentCid(), root.getCatId()))
                .peek(q -> setChildren(q, all))
                .sorted(Comparator.comparingInt(CategoryEntity::getSort))
                .collect(Collectors.toList());
        root.setChildren(collect);
    }

    @Override
    public void removeMenuByIds(List<Long> asList) {
        baseMapper.deleteBatchIds(asList);
    }

    @Override
    public Long[] getPathByCatId(Long catelogId) {
        List<Long> result = new ArrayList<>();
        setCategoryPath(catelogId, result);
        Collections.reverse(result);
        return result.toArray(new Long[result.size()]);
    }

    @Override
    @Cacheable(cacheNames = {"category"}, key = "#root.method.name")
    public List<CategoryEntity> listRootLevel() {
        System.out.println("查询数据库...");
        return baseMapper.selectList(new QueryWrapper<CategoryEntity>()
                .eq("parent_cid", 0));
    }


    @Override
    @Cacheable(cacheNames = {"category"}, key = "#root.methodName")
    public Map<String, List<Catalog2Vo>> getCatalogJson() {
        // 缓存中没有，从数据库中查找数据
        return getCatalogJsonFromDb();
    }

    public Map<String, List<Catalog2Vo>> getCatalogJson2() {
        // 先从缓存中查找数据
        String catalogJson = stringRedisTemplate.opsForValue().get(CATALOG_JSON);
        if (StrUtil.isEmpty(catalogJson)) {
            // 缓存中没有，从数据库中查找数据
            Map<String, List<Catalog2Vo>> catalogJsonFromDb = getCatalogJsonFromDb();
            String jsonString = JSON.toJSONString(catalogJsonFromDb);
            // 将数据放入redis中
            stringRedisTemplate.opsForValue().set(CATALOG_JSON, jsonString);
            return catalogJsonFromDb;
        }
        // 缓存有，直接返回缓存中数据
        return JSON.parseObject(catalogJson, new TypeReference<Map<String, List<Catalog2Vo>>>(){});
    }

    public Map<String, List<Catalog2Vo>> getCatalogJsonFromDb() {
        List<CategoryEntity> categoryEntities = baseMapper.selectList(null);
        // 找到一级商品目录，组装成树结构返回
        return categoryEntities.stream()
                .filter(q -> q.getParentCid() == 0)
                .map(l1 -> {
                    // 获取所有2级分类的商品目录
                    List<Catalog2Vo> catalog2List = categoryEntities.stream()
                            .filter(l2 -> Objects.equals(l2.getParentCid(), l1.getCatId()))
                            .map(l2 -> {
                                // 获取所有的三级分类的商品目录
                                List<Catalog3Vo> collect = categoryEntities.stream()
                                        .filter(l3 -> Objects.equals(l3.getParentCid(), l2.getCatId()))
                                        .map(l3 ->
                                                Catalog3Vo.builder()
                                                        .catalog2Id(l2.getCatId().toString())
                                                        .id(l3.getCatId().toString())
                                                        .name(l3.getName())
                                                        .build())
                                        .collect(Collectors.toList());
                                return Catalog2Vo.builder()
                                        .catalog1Id(l1.getCatId().toString())
                                        .id(l2.getCatId().toString())
                                        .name(l2.getName())
                                        .catalog3List(collect)
                                        .build();
                            })
                            .collect(Collectors.toList());
                    return Catalog1Vo.builder().id(l1.getCatId().toString())
                            .catalog2List(catalog2List).build();
                })
                .collect(Collectors.toMap(Catalog1Vo::getId, Catalog1Vo::getCatalog2List));
    }

    private void setCategoryPath(Long catelogId, List<Long> result) {
        result.add(catelogId);
        CategoryEntity entity = baseMapper.selectById(catelogId);
        if (entity.getParentCid() != 0) {
            setCategoryPath(entity.getParentCid(), result);
        }
    }
}